package com.app.aop;

import com.app.aop.has.HasApiLimit;
import com.app.exception.BusinessException;
import com.app.framework.utils.IpUtils;
import com.app.framework.utils.RedisUtils;
import jakarta.servlet.http.HttpServletRequest;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import java.lang.reflect.Method;
import java.util.concurrent.TimeUnit;

/**
 * 接口请求频率限制
 */
@Aspect
@Component
public class ApiLimit {

    /**
     * 定义一个切点（通过注解）
     */
    @Pointcut("@annotation(com.app.aop.has.HasApiLimit)")
    public void HasApiLimit() {
    }

    /**
     * Aop切面方法
     *
     * @param joinPoint 切点
     */
    @Before("HasApiLimit()")
    public void interceptorDo(JoinPoint joinPoint) {
        MethodSignature signature = (MethodSignature) joinPoint.getSignature();
        Method method = signature.getMethod();
        HasApiLimit hasApiLimit = method.getDeclaredAnnotation(HasApiLimit.class);
        int seconds = hasApiLimit.seconds();
        int maxCount = hasApiLimit.maxCount();
        HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.currentRequestAttributes()).getRequest();
        String ip = IpUtils.getIp();
        String api = request.getRequestURI();
        String key = "HasApiLimit:" + ip + ":" + api;
        if (!RedisUtils.hasKey(key)) {
            RedisUtils.set(key, 1, seconds, TimeUnit.MINUTES);
        } else {
            int count = RedisUtils.get(key);
            if (count >= maxCount) {
                throw new BusinessException("接口使用频率过高," + seconds + "分钟后再试!");
            } else {
                RedisUtils.increment(key, 1);
            }
        }
    }

}